/**
 * @brief 3.5.4 C风格字符串
 * 尽管C++支持C风格字符串，但在C++程序中最好还是不要使用它们。
 * 这是因为C风格字符串不仅使用起来不太方便，而且极易引发程序漏洞，是诸多安全问题的根本原因
 * C语言标准库提供的一组函数，这些函数可用于操作C风格字符串，它们定义在cstring头文件中，cstring是C语言头文件string.h的C++版本
 */
#include <iostream>
#include <cstring> // 可用于操作C风格字符串的函数，它们定义在cstring头文件中
using std::cin, std::cout, std::endl;
using std::string;

int main(int argc, char const *argv[])
{
    // C风格字符串函数，不负责验证其字符串参数
    char ca[] = {'C', '+', '+'}; // 未以空字符'\0'结尾
    cout << strlen(ca) << endl;  // 严重错误，没有以空字符结束
    // strlen函数将有可能沿着ca在内存中的位置不断向前寻找，直到遇到空字符才停下来。
    char ca1[] = {'C', '+', '+', '\0'}; // 以空字符'\0'结尾
    cout << strlen(ca1) << endl;        // 输出3

    // 比较字符串
    // 比较两个C风格字符串的方法和之前学习过的比较标准库string对象的方法大相径庭。
    // 比较标准库string对象的时候，用的是普通的关系运算符和相等性运算符：
    string s1 = "abcd", s2 = "Abde";
    if (s1 < s2)
        cout << "s1 < s2" << endl;
    else
        cout << "s1 > s2" << endl;
    // 如果把这些运算符用在两个C风格字符串上，实际比较的将是指针而非字符串本身
    const char ca11[] = "abcd", ca21[] = "Abde";
    // if (ca11 < ca21) // 未定义的，试图比较两个无关的地址

    // 要想比较两个C风格字符串需要调用strcmp函数
    if (strcmp(ca11, ca21) < 0) // 如果前面的字符串较大，返回正值；如果后面的字符串较大，返回负值
        cout << "ca11 < ca21" << endl;
    else
        cout << "ca11 > ca21" << endl;

    // 连接或拷贝C风格字符串也与标准库string对象的同类操作差别很大。
    string largeStr = s1 + " " + s2;
    // 同样的操作如果放到ca11和ca21这两个数组身上就会产生错误了。
    // 表达式ca11 + ca21试图将两个指针相加，显然这样的操作没什么意义，也肯定是非法的。
    // 正确的方法是使用strcat函数和strcpy函数。
    char largeChar[10];      // 该数组必须足够大以便容纳下结果字符串及末尾的空字符。
    strcpy(largeChar, ca11); // 把ca11拷贝给largeChar
    strcat(largeChar, " ");  // 在largeChar末尾加上一个空格
    strcat(largeChar, ca21); // 把ca21连接到后面

    // 对大多数应用来说，使用标准库string要比使用C风格字符串更安全、更高效。

    return 0;
}
